package com.zbkj.admin.boot.servlet.listener;

import com.zbkj.admin.boot.context.MicaContextProperties;
import com.zbkj.admin.boot.context.MicaHttpHeadersGetter;
import com.zbkj.admin.boot.servlet.context.MicaServletContext;
import com.zbkj.admin.boot.servlet.context.ServletHttpHeadersGetter;
import jakarta.servlet.ServletRequestEvent;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import net.dreamlu.mica.core.constant.MicaConstant;
import net.dreamlu.mica.core.utils.StringUtil;
import net.dreamlu.mica.core.utils.ThreadLocalUtil;
import org.slf4j.MDC;
import org.springframework.http.HttpHeaders;

/**
 * Servlet 请求监听器
 *
 * @author L.cm
 */
@RequiredArgsConstructor
public class ServletRequestListener implements jakarta.servlet.ServletRequestListener {
	private final MicaContextProperties contextProperties;
	private final MicaHttpHeadersGetter httpHeadersGetter;

	@Override
	public void requestInitialized(ServletRequestEvent event) {
		HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
		// 1. 记录请求开始时间
		request.setAttribute(MicaConstant.REQUEST_START_TIME, System.nanoTime());
		MicaContextProperties.Headers headers = contextProperties.getHeaders();
		// 2. 网关透传下来的的账号 id
		String accountId = request.getHeader(headers.getNameAccountId());
		if (StringUtil.isNotBlank(accountId)) {
			MDC.put(MicaConstant.MDC_ACCOUNT_ID_KEY, accountId);
		}
		// 3. 获取透传的 requestId，没有时生成一个，并且设置到上下文
		String nameRequestId = headers.getNameRequestId();
		String requestId = request.getHeader(nameRequestId);
		HttpHeaders httpHeaders = ((ServletHttpHeadersGetter) httpHeadersGetter).get(request);
		if (StringUtil.isBlank(requestId)) {
			requestId = StringUtil.getUUID();
			httpHeaders.add(nameRequestId, requestId);
		}
		MDC.put(MicaConstant.MDC_REQUEST_ID_KEY, requestId);
		// 4. 然后处理 context，直接传递 request，因为 spring 中的尚未初始化完成
		ThreadLocalUtil.put(MicaServletContext.CONTEXT_KEY, httpHeaders);
	}

	@Override
	public void requestDestroyed(ServletRequestEvent event) {
		// 会话销毁是，清除上下文
		ThreadLocalUtil.clear();
		// 清除 mdc
		MDC.remove(MicaConstant.MDC_ACCOUNT_ID_KEY);
		MDC.remove(MicaConstant.MDC_REQUEST_ID_KEY);
	}

}
